// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Configuration;
using ValidationAspects.Sdk;

namespace TestValidationAspects.Configuration
{
	[TestFixture]
	public class TestTypeValidation
	{
		[SetUp]
		public void SetUp()
		{
			TestHelpers.ResetFramework();
		}

		[Test]
		public void Test_Configure_throws_for_null_Type_property()
		{
			Test.Throws<ValidationConfigurationException>(() => new TypeValidation().Configure(), "Type has not been declared for Type Validation.");
		}

		[Test]
		public void Test_Configure_with_Apply_Add_adds_factories()
		{
			MockValidatorFactory<Dummy> factoryA = new MockValidatorFactory<Dummy>();
			Assert.IsNull(factoryA.Value);

			typeof(Dummy).ReplaceValidation(new[] {factoryA});

			MockValidatorFactory<Dummy> factoryB = new MockValidatorFactory<Dummy>();
			Assert.IsNull(factoryB.Value);

			TypeValidation typeValidation = new TypeValidation {Apply = ValidationApplication.Add, Type = typeof(Dummy), Validators = new List<IValidatorFactory> {factoryB}};

			typeValidation.Configure();

			Dummy value = new Dummy();
			IValidationContext context = new MockValidationContext();
			typeof(Dummy).ResolveValidator().Invoke(value, context);

			factoryA.TestState(value, context);
			factoryB.TestState(value, context);
		}

		[Test]
		public void Test_Configure_with_Apply_Replace_replaces_factories()
		{
			MockValidatorFactory<Dummy> factoryA = new MockValidatorFactory<Dummy>();
			Assert.IsNull(factoryA.Value);

			typeof(Dummy).ReplaceValidation(new[] {factoryA});

			MockValidatorFactory<Dummy> factoryB = new MockValidatorFactory<Dummy>();
			Assert.IsNull(factoryB.Value);

			TypeValidation typeValidation = new TypeValidation {Apply = ValidationApplication.Replace, Type = typeof(Dummy), Validators = new List<IValidatorFactory> {factoryB}};

			typeValidation.Configure();

			Dummy value = new Dummy();
			IValidationContext context = new MockValidationContext();
			typeof(Dummy).ResolveValidator().Invoke(value, context);

			factoryA.TestState(null, null);
			factoryB.TestState(value, context);
		}

		[Test]
		public void Test_Configure_with_no_supplied_validators_returns_null()
		{
			new TypeValidation {Type = typeof(Dummy)}.Configure();
			Assert.IsNull(typeof(Dummy).ResolveValidator());
		}

		[Test]
		public void Test_Configure_correctly_calls_onto_supplier_IPropertyValidation_instances()
		{
			var mock = new MockPropertyValidation();
			Assert.IsNull(mock.Type);

			new TypeValidation {Type = typeof(Dummy), Properties = new List<IPropertyValidation> {mock}}.Configure();

			Assert.AreSame(typeof(Dummy), mock.Type);
		}

		[Test]
		public void Test_Configure_correctly_calls_onto_supplier_IMethodValidation_instances()
		{
			var mock = new MockMethodValidation();
			Assert.IsNull(mock.Type);

			new TypeValidation {Type = typeof(Dummy), Methods = new List<IMethodValidation> {mock}}.Configure();

			Assert.AreSame(typeof(Dummy), mock.Type);
		}

		#region Mocks
		public class Dummy {}

		public class MockPropertyValidation : IPropertyValidation
		{
			public Type Type { get; set; }

			#region Implementation of IPropertyValidation
			public void Register(Type type)
			{
				Type = type;
			}
			#endregion
		}

		public class MockMethodValidation : IMethodValidation
		{
			public Type Type { get; set; }

			#region Implementation of IMethodValidation
			public void Register(Type type)
			{
				Type = type;
			}
			#endregion
		}
		#endregion
	}
}